package com.wlwx.simulator;

import com.wlwx.simulator.codec.CMPPCommand;
import com.wlwx.simulator.message.outbound.DeliverOutBoundRequest;
import com.wlwx.simulator.message.inbound.SubmitInBoundRequest;
import com.wlwx.simulator.util.Cache;
import com.wlwx.simulator.util.GenerateIdUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.Attribute;

import java.nio.ByteBuffer;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;

import static com.wlwx.simulator.handle.CMPP20ServerHandle.CMPP_LOGIN_SOURCE_ADDR_KEY;

public class ReportThread implements Runnable {
    private static volatile ReportThread instance;

    //65535个号码不断循环
    private static volatile short index = 0;
    private static byte[] DELIVER_BYTES = "DELIVRD".getBytes();

    private ReportThread() {
        Thread t = new Thread(this);
        t.setName("Report-Thread");
        t.setDaemon(true);
        t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                System.out.println(t.getName() + " Thread cause error , mess: " + e.getMessage());
                e.printStackTrace();
            }
        });
        t.start();
    }

    public static ReportThread get() {
        if(instance == null) {
            synchronized (ReportThread.class) {
                if(instance == null) {
                    instance = new ReportThread();
                }
            }
        }

        return instance;
    }

    @Override
    public void run() {
        Cache cache = Cache.get();
        while (true) {
            Map<ChannelHandlerContext, BlockingQueue<SubmitInBoundRequest>> map = cache.getSubmitReq();
            for(Map.Entry<ChannelHandlerContext, BlockingQueue<SubmitInBoundRequest>> entry : map.entrySet()) {

                ChannelHandlerContext                 ctx = entry.getKey();
                BlockingQueue<SubmitInBoundRequest> queue = entry.getValue();
                Attribute<Integer>         sourceAddrAttr = ctx.channel().attr(CMPP_LOGIN_SOURCE_ADDR_KEY);
                int                            sourceAddr = sourceAddrAttr.get();
                List<SubmitInBoundRequest>           list = new ArrayList<>(50);

                queue.drainTo(list, 50);
                if(!ctx.isRemoved()) {
                    if(list.size() > 0) {
                        for(SubmitInBoundRequest request : list) {
                            DeliverOutBoundRequest deliverOutBoundRequest = getDeliverRequest(sourceAddr, request);
                            ctx.writeAndFlush(CMPPCommand.createCommand(deliverOutBoundRequest));
                            /*// 把deliverRequest加入到结果等待map中 用于重试
                            cache.addSubmitReqToWaitSubmitMap(ctx, request);*/
                            System.out.println(deliverOutBoundRequest);
                        }
                    }
                } else {
                    System.out.println(ctx + " is removed!");
                    map.remove(ctx);
                }
            }

            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            continue;
        }
    }

    private DeliverOutBoundRequest getDeliverRequest(int sourceAddr, SubmitInBoundRequest submitRequest) {
        DeliverOutBoundRequest request = new DeliverOutBoundRequest(index++ & 0xFFFF );
        request.setMsgId(GenerateIdUtil.generateMsgId(sourceAddr));
        request.setDestId(submitRequest.getDestTerminalId());
        request.setServiceId(submitRequest.getServiceId());
        request.setTpPid(submitRequest.getTpPid());
        request.setTpUdhi(submitRequest.getTpPid());
        request.setSrcTerminalId(submitRequest.getSrcId());
        request.setRegisteredDelivery((byte) 1);
        request.setMsgLength((byte) 60);
        request.setMsgContent(getDeliverReportByte(submitRequest));
        request.setReversed(String.format("%06d", 0));
        return request;
    }

    private byte[] getDeliverReportByte(SubmitInBoundRequest submitRequest) {
        ByteBuffer byteBuffer = ByteBuffer.allocate(60);
        byteBuffer.putLong(submitRequest.getMsgId())
                .put(DELIVER_BYTES)
                .put(getTimeBytes())
                .put(getTimeBytes())
                .put(submitRequest.getDestTerminalId().getBytes())
                .putInt(0);
        return byteBuffer.array();
    }

    private byte[] getTimeBytes () {
        LocalDate localDate = LocalDate.now();
        LocalTime localTime = LocalTime.now();

        int year = localDate.getYear();
        int month = localDate.getMonthValue();
        int day = localDate.getDayOfMonth();

        int hour = localTime.getHour();
        int monite = localTime.getMinute();

        String timeStr = String.format("%02d%02d%02d%02d%02d" ,year%100, month, day, hour, monite);

        return timeStr.getBytes();
    }

}
